package com.base.cn.platform.os.common.mybatis.utils;

import com.base.cn.platform.os.common.utils.DateUtils;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;

import java.util.Date;
import java.util.List;

/**
 * MyBatisSqlUtils
 *
 * @author s.li
 * @date 2019/04/11
 */
public class MyBatisSqlUtils {
    private static ReflectorFactory reflectorFactory = new DefaultReflectorFactory();
    private static ObjectFactory objectFactory = new DefaultObjectFactory();
    private static ObjectWrapperFactory objectWrapperFactory = new DefaultObjectWrapperFactory();

    /**
     * 运行期获取MyBatis执行的SQL及参数
     *
     * @param mappedStatement
     * @param boundSql      参数
     * @return MyBatisSql
     */
    public static MyBatisSql getMyBatisSql(MappedStatement mappedStatement, BoundSql boundSql) {

        MyBatisSql iBatisSql = new MyBatisSql();
        iBatisSql.setSql(boundSql.getSql());
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (parameterMappings != null) {
            Object[] parameterArray = new Object[parameterMappings.size()];
            ParameterMapping parameterMapping;
            Object value;
            Object parameterObject = boundSql.getParameterObject();
            MetaObject metaObject;
            PropertyTokenizer prop;
            String propertyName;
            for (int i = 0; i < parameterMappings.size(); i++) {
                parameterMapping = parameterMappings.get(i);
                if (parameterMapping.getMode() != ParameterMode.OUT) {
                    propertyName = parameterMapping.getProperty();
                    metaObject = MetaObject.forObject(parameterObject,objectFactory,objectWrapperFactory,reflectorFactory);
                    prop = new PropertyTokenizer(propertyName);
                    if (parameterObject == null) {
                        value = null;
                    } else if (mappedStatement.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass())) {
                        value = parameterObject;
                    } else if (boundSql.hasAdditionalParameter(propertyName)) {
                        value = boundSql.getAdditionalParameter(propertyName);
                    } else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX) && boundSql.hasAdditionalParameter(prop.getName())) {
                        value = boundSql.getAdditionalParameter(prop.getName());
                        if (value != null) {
                            value = MetaObject.forObject(value,objectFactory,objectWrapperFactory,reflectorFactory).getValue(propertyName.substring(prop.getName().length()));
                        }
                    } else {
                        if(metaObject.getValue(propertyName) instanceof String){
                            value = "'"+metaObject.getValue(propertyName)+"'";
                        } else if(metaObject.getValue(propertyName) instanceof Date){
                            value = "'"+DateUtils.format((Date) metaObject.getValue(propertyName),"yyyy-MM-dd HH:mm:ss")+"'";
                        }else {
                            value = metaObject == null ? null : metaObject.getValue(propertyName);
                        }
                    }
                    parameterArray[i] = value;
                }
            }
            iBatisSql.setParameters(parameterArray);
        }
        return iBatisSql;
    }
}